﻿
namespace Sai.Core
{
    using Sai.Core.Introspection;
    using System;

    /// <summary>
    /// Calculates a measure of how much has changed in a class, assembly or in total.
    /// </summary>
    public class ChurnCalculator
    {
        public ChurnCalculator()
        {
        }

        /// <summary>
        /// No changes to assemblies, just increment total.
        /// </summary>
        /// <param name="oldVersion"></param>
        /// <param name="newVersion"></param>
        public ChurnCalculator(IntrospectedAssembly oldVersion, IntrospectedAssembly newVersion)
            : this(oldVersion.TypeCount + newVersion.TypeCount, 0, 0, 0)
        {
        }

        public ChurnCalculator(IntrospectedAssembly oldVersion, IntrospectedAssembly newVersion, IAssemblyDifference difference)
            : this(oldVersion.TypeCount + newVersion.TypeCount, 
            difference.RemovedTypes == null ? 0 : difference.RemovedTypes.Count, 
            difference.AddedTypes == null ? 0 : difference.AddedTypes.Count,
            difference.ChangedTypes == null ? 0 : difference.ChangedTypes.Count)
        {
        }

        public ChurnCalculator(int total, int removed, int added, int changed)
        {
            this.Total = total;
            this.Removed = removed;
            this.Added = added;
            this.Changed = changed;
        }

        private int Total { get; set; }

        private int Removed { get; set; }

        private int Added { get; set; }

        private int Changed { get; set; }

        public void IncrementTotal(int by)
        {
            this.Total += by;
        }

        public void IncrementRemoved(int by)
        {
            this.Removed += by;
        }

        public void IncrementAdded(int by)
        {
            this.Added += by;
        }

        public void IncrementChanged(int by)
        {
            this.Changed += by;
        }

        public void Increment(ChurnCalculator child)
        {
            this.IncrementAdded(child.Added);
            this.IncrementChanged(child.Changed);
            this.IncrementRemoved(child.Removed);
            this.IncrementTotal(child.Total);
        }

        public int Calculate()
        {
            this.Total = Math.Max(this.Added + this.Removed, this.Total);

            if (this.Total == 0)
                return 0;

            return (100 * (this.Added + this.Removed + (2 * this.Changed))) / this.Total;
        }
    }
}
